import {computed, designPage, onBeforeUnmount, onMounted, reactive, useRefs} from "plain-ui-composition";

import {PublicApp} from "../PublicRoot";
import {DocHomeHead} from "./components/DocHomeHead";
import {DocHomeMenu} from "./components/DocHomeMenu";
import './IndexApp.scss'
import {AppNavigator, AppNavigatorComponent} from "./natigator/app-navigator";
import {debounce} from "plain-utils/utils/debounce";
import {AppNavigatorUtils, AppRoute} from "./natigator/app-navigator.utils.";
import {PlScroll} from "plain-ui";
import {classnames} from "plain-utils/dom/classnames";

export const IndexApp = designPage(() => {

    const {refs, onRef} = useRefs({
        content: HTMLElement,
    })

    const state = reactive({
        navList: [] as { top: number, name: string }[],
        scrollTop: 0,
    })

    /**
     * 当前锚点索引
     * @author  韦胜健
     * @date    2020/9/17 11:04
     */
    const activeNavIndex = computed(() => {
        for (let i = state.navList.length - 1; i >= 0; i--) {
            const navItem = state.navList[i];
            if (state.scrollTop >= navItem.top) {
                return i
            }
        }
    })
    const methods = {
        scrollTop: (top: number) => {
            document.documentElement.scrollTop = top
        },
        /**
         * 刷新锚点扫描数组
         * @author  韦胜健
         * @date    2020/9/17 11:04
         */
        refreshNavList: debounce(() => {
            if (!refs.content) {
                return
            }
            const h2List = Array.from(refs.content.querySelectorAll('h2')) as HTMLElement[]
            state.navList = h2List.map((h1, index) => {
                let {offsetTop, innerText} = h1
                innerText = innerText.replace(/在线调试.*/, '').trim()
                return {
                    top: index === 0 ? 0 : offsetTop,
                    name: innerText,
                }
            }).filter(item => !!item.name)
            methods.scrollByHash(AppNavigatorUtils.getRoute())
        }, 100, false),

        /**
         * 根据锚点定位
         * @author  韦胜健
         * @date    2020/9/17 11:15
         */
        scrollByHash: ({hash}: AppRoute) => {
            if (!hash) {
                if (!!state.navList && state.navList.length > 0) {
                    hash = state.navList[0].name
                }
            }
            // 页面锚点定位
            for (let i = 0; i < state.navList.length; i++) {
                const navItem = state.navList[i];
                if (navItem.name === hash) {
                    return methods.scrollTop(navItem.top + 1 - (60 + 16))
                }
            }
        }
    }

    const handler = {
        /**
         * 监听scrollTop事件
         * @author  韦胜健
         * @date    2020/9/17 11:04
         */
        onScrollTop: () => {
            state.scrollTop = document.documentElement.scrollTop
        },
        /**
         * 处理点击锚点触发定位事件
         * @author  韦胜健
         * @date    2020/9/17 11:04
         */
        onClickNavItem: (name: string) => {
            const {path, hash} = AppNavigator.route
            if (name === hash) {
                methods.scrollByHash(AppNavigator.route)
            } else {
                AppNavigator.go(path, name)
            }
        },
        onHashChange: (route: AppRoute) => methods.scrollByHash(route),
        onPageReady: () => {
            methods.refreshNavList()
            if (!AppNavigator.route.hash) {
                methods.scrollTop(0)
            }
        },
        onClickLink: (e: MouseEvent) => {
            const el = e.target as HTMLElement

            if (el.tagName === 'A' || (!!el.parentElement && el.parentElement.tagName === 'A')) {
                const linkEl = el.tagName === 'A' ? el : el.parentElement!
                const href = linkEl.getAttribute('href')
                if (!!href) {
                    const match = href.match(/~(.*)/)
                    if (!!match) {
                        let [, path] = match
                        path = decodeURIComponent(path)
                        AppNavigator.go(path)
                    } else if (href.indexOf('TYPE ') === 0) {
                        AppNavigator.go(AppNavigator.route.path, href)
                    } else {
                        window.open(href)
                    }
                }
                e.preventDefault()
                e.stopPropagation()
                return
            }
            if (el.tagName === 'H2' || el.parentElement!.tagName === 'H2') {
                if (el.tagName === 'H2' && !!el.firstElementChild && el.firstElementChild.tagName === 'SPAN') {
                    return;
                }
                let anchorEl = el.tagName === 'H2' ? el : el.parentElement!
                const span = anchorEl.querySelector('span')
                const text = !!span ? span.innerText : anchorEl.innerText
                AppNavigator.go(AppNavigator.route.path, text)
            }
        }
    }

    const ejectHashListener = AppNavigator.event.on.onPageReady(handler.onPageReady)
    const ejectPathListener = AppNavigator.event.on.onHashChange(handler.onHashChange)

    onMounted(() => {
        handler.onPageReady()
        window.addEventListener('click', handler.onClickLink, true)
        window.addEventListener('scroll', handler.onScrollTop)
    })
    onBeforeUnmount(() => {
        ejectHashListener()
        ejectPathListener()
        window.removeEventListener('click', handler.onClickLink, true)
        window.removeEventListener('scroll', handler.onScrollTop)
    })

    return () => (
        <PublicApp>
            <article class={'doc-home'}>
                <DocHomeHead/>
                <DocHomeMenu/>
                <div class="doc-home-anchor">
                    <PlScroll fitHostWidth>
                        <ul class="doc-home-anchor-list">
                            {state.navList.map((item, index) => (
                                <li key={index} class={classnames({'doc-home-anchor-active': index === activeNavIndex.value})}
                                    onClick={() => handler.onClickNavItem(item.name)}>
                                    <div class="doc-home-anchor-tag">
                                        <i class="doc-home-anchor-tag-inner"/>
                                    </div>
                                    <span class="doc-home-anchor-index">{index + 1}、</span>
                                    <span>{item.name}</span>
                                </li>
                            ))}
                        </ul>
                    </PlScroll>
                </div>
                <section class={'doc-content'} ref={onRef.content}>
                    <AppNavigatorComponent defaultPath="home/introduce.entire"/>
                </section>
            </article>
        </PublicApp>
    )
})
